﻿/****************************** Module Header ******************************\
 * Module Name:  WSDLHelper.cs
 * Module Version:  1.0.0 (2013-6-19)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to process the webservices.
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Web.Services.Description;

namespace UCL
{
    /// <summary>
    /// WSDL助手类
    /// <para>如：</para>
    /// <para>WSDLHelper.Uri = "http://myhost.com:8080/wsSeatClient.asmx";</para>
    /// <para>WSDLHelper.GetInstance();</para>
    /// <para>if (!WSDLHelper.Enable)</para>
    /// <para>{</para>
    /// <para>    WSDLHelper.ShowMessage("Login_Connect");</para>
    /// <para>    return;</para>
    /// <para>}</para>
    /// </summary>
    /// <remarks>2013-6-19 by sutroon</remarks>
    public class WSDLHelper
    {
        /// <summary>
        /// WebServices地址
        /// </summary>
        public static string Uri { get; set; }

        // WebServices实例对象
        private static Type Instance;

        /// <summary>
        /// 异常对象实例
        /// </summary>
        public static Exception ExceptionObject { get; set; }

        /// <summary>
        /// 获取或设置显示消息的委托方法
        /// </summary>
        public static Action<string> ShowMessageHandler { get; set; }

        /// <summary>
        /// 获取或设置WebServices是否可用
        /// </summary>
        public static bool Enable { get; set; }

        /// <summary>
        /// 获取或设置是否调试模式
        /// </summary>
        /// <remarks>2014-4-10 by sutroon</remarks>
        public static bool IsDebug { get; set; }

        /// <summary>
        /// 对返回值判断：if(obj is Exception) MessageBox.Show(((Exception)obj).Message);
        /// </summary>
        /// <param name="namespace"></param>
        /// <returns></returns>
        public static object GetInstance(string @namespace = "sowsdl")
        {
            try
            {
                //获取WSDL
                WebClient wc = new WebClient();
                Stream stream = wc.OpenRead(Uri + "?WSDL");
                ServiceDescription sd = ServiceDescription.Read(stream);
                string classname = sd.Services[0].Name;
                ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
                sdi.AddServiceDescription(sd, "", "");
                CodeNamespace cn = new CodeNamespace(@namespace);

                //生成客户端代理类代码
                CodeCompileUnit ccu = new CodeCompileUnit();
                ccu.Namespaces.Add(cn);
                sdi.Import(cn, ccu);
                CSharpCodeProvider csc = new CSharpCodeProvider();
                //ICodeCompiler icc = csc.CreateCompiler();

                //设定编译参数
                CompilerParameters cplist = new CompilerParameters();
                cplist.GenerateExecutable = false;
                cplist.GenerateInMemory = true;
                cplist.ReferencedAssemblies.Add("System.dll");
                cplist.ReferencedAssemblies.Add("System.XML.dll");
                cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
                cplist.ReferencedAssemblies.Add("System.Data.dll");

                //编译代理类
                CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
                if (true == cr.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }
                    throw new Exception(sb.ToString());
                }

                //生成代理实例，并调用方法
                System.Reflection.Assembly assembly = cr.CompiledAssembly;
                Instance = assembly.GetType(@namespace + "." + classname, true, true);
                ExceptionObject = null;
                Enable = true;
                return Instance;
            }
            catch (Exception ex)
            {
                ExceptionObject = ex;
                Enable = false;
                return ex;
            }
        }

        /// <summary>
        /// 调用方法
        /// </summary>
        /// <param name="methodname"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static object InvokeMethod(string methodname, object[] args)
        {
            if (Instance == null)
            {
                GetInstance();
                if (Instance == null)
                {
                    ExceptionObject = new Exception("远程服务器未连接");
                    return null;
                }
            }
            try
            {
                object obj = Activator.CreateInstance(Instance);
                System.Reflection.MethodInfo mi = Instance.GetMethod(methodname);
                ExceptionObject = null;
                return mi.Invoke(obj, args);
            }
            catch (Exception ex)
            {
                ExceptionObject = ex;
                return ex;
            }
        }

        /// <summary>
        /// 调用泛型方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="methodname"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static T InvokeMethod<T>(string methodname, object[] args)
        {
            if (Instance == null)
            {
                GetInstance();
                if (Instance == null)
                {
                    ExceptionObject = new Exception("远程服务器未连接");
                    return default(T);
                }
            }
            try
            {
                object obj = Activator.CreateInstance(Instance);
                System.Reflection.MethodInfo mi = Instance.GetMethod(methodname);
                ExceptionObject = null;
                object result = mi.Invoke(obj, args);
                if (result.GetType() == typeof(T))
                {
                    return (T)result;
                }
                else
                {
                    return default(T);
                }
            }
            catch (Exception ex)
            {
                ExceptionObject = ex;
            }
            return default(T);
        }

        /// <summary>
        /// 显示wsdlHelper错误消息
        /// </summary>
        /// <param name="funcName"></param>
        public static void ShowMessage(string funcName)
        {
            if (ShowMessageHandler != null) ShowMessageHandler(GetExceptionMessage("[{0}]数据读取失败,原因是:".Fmt(funcName)));
        }

        /// <summary>
        /// 销毁资源
        /// </summary>
        public static void Dispose()
        {
            ExceptionObject = null;
            Instance = null;
        }

        /// <summary>
        /// 获取异常消息
        /// </summary>
        /// <param name="funcName">当前调用的方法名称,用于方便出错定位</param>
        /// <param name="title"></param>
        /// <param name="ln"></param>
        /// <param name="showAllErr"></param>
        /// <returns></returns>
        public static string GetExceptionMessage(string funcName, string title = "调用失败,原因是", string ln = null)
        {
            if (ExceptionObject == null) return "UnFound Exception!";
            if (ln == null) ln = Environment.NewLine;
            StringBuilder sb = new StringBuilder();
            if (title.Length > 0) sb.AppendFormat("{0} - {1}：{2}", funcName, title, ln);
            sb.AppendFormat("{0}{1}", ExceptionObject.Message, ln);
            if (ExceptionObject.InnerException != null)
            {
                if (IsDebug)
                {
                    sb.Append(ExceptionObject.InnerException.Message);
                }
                else
                {
                    int i = ExceptionObject.InnerException.Message.IndexOf("\n");
                    if (i > -1) sb.Append(ExceptionObject.InnerException.Message.Substring(0, i));
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 实例化WebServices
        /// <para>返回类型结果或Exception对象</para>
        /// </summary>
        /// <param name="url">WebServices地址,如：http://localhost/InvokeService/Service1.asmx</param>
        /// <param name="methodname">调用的方法</param>
        /// <param name="args">把webservices里需要的参数按顺序放到这个object[]里</param>
        /// <param name="namespace">这里的namespace是需引用的webservices的命名空间</param>
        /// <remarks>
        /// 如果方法参数有ref或out参数，格式如下(参数自动排列顺序是普通参数=ref参数>out参数)：
        /// WSDL定义方法:
        /// [WebMethod]
        /// public DataTable TestMethod(Guid id,out int x,out int y,ref int z,ref string code,string name);
        /// 调用方法：
        /// int x=0,y=0,z=0;string code="yes";
        /// object[] args=new object[]{ Guid.NewGuid(),z,code, "sutroon",x,y  };// 自动顺序 id,ref z,ref code,name,out x,out y
        /// object dt=InvokeWebService(url,"TestMethod",args);
        /// x=args[4];
        /// y=args[5];
        /// </remarks>
        public static object InvokeWebService(string url, string methodname, object[] args, string @namespace = "sowsdl")
        {
            try
            {
                //获取WSDL
                WebClient wc = new WebClient();
                Stream stream = wc.OpenRead(url + "?WSDL");
                ServiceDescription sd = ServiceDescription.Read(stream);
                string classname = sd.Services[0].Name;
                ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
                sdi.AddServiceDescription(sd, "", "");
                CodeNamespace cn = new CodeNamespace(@namespace);

                //生成客户端代理类代码
                CodeCompileUnit ccu = new CodeCompileUnit();
                ccu.Namespaces.Add(cn);
                sdi.Import(cn, ccu);
                CSharpCodeProvider csc = new CSharpCodeProvider();
                //ICodeCompiler icc = csc.CreateCompiler();

                //设定编译参数
                CompilerParameters cplist = new CompilerParameters();
                cplist.GenerateExecutable = false;
                cplist.GenerateInMemory = true;
                cplist.ReferencedAssemblies.Add("System.dll");
                cplist.ReferencedAssemblies.Add("System.XML.dll");
                cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
                cplist.ReferencedAssemblies.Add("System.Data.dll");

                //编译代理类
                CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
                if (true == cr.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }
                    throw new Exception(sb.ToString());
                }

                //生成代理实例，并调用方法
                System.Reflection.Assembly assembly = cr.CompiledAssembly;
                Type t = assembly.GetType(@namespace + "." + classname, true, true);
                object obj = Activator.CreateInstance(t);
                System.Reflection.MethodInfo mi = t.GetMethod(methodname);

                Enable = true;
                return mi.Invoke(obj, args);
            }
            catch (Exception ex)
            {
                ExceptionObject = ex;
                Enable = false;
                return ex;
            }
        }
    }
}
